
/**
\file
Defines the rainbow::draw_information class.
\author Sean Tromans
*/

#include <sun_pre_compiled.hpp>
#include <rainbow/draw_information/draw_information.hpp>

#if !defined(SUN_DISABLE_LUA)
#include <sun/lua/lua.hpp>
#endif

namespace rainbow
{

	/**
	Default Constructor.
	\author Sean Tromans
	*/
	draw_information::draw_information( )
		:		device(nullptr)

			,	blend_handle(1)
			,	culling_handle(1)
			,	depth_handle(1)
			,	stencil_handle(1)
	{
	}

	/**
	Constructor.
	@param device The graphics device this draw_information is intended for.
	\author Sean Tromans
	*/
	draw_information::draw_information( graphics_device & device )
		:		device(&device)

			,	blend_handle(1)
			,	culling_handle(1)
			,	depth_handle(1)
			,	stencil_handle(1)
	{
	}

	/**
	Determines whether the draw_information is valid.
	\author Sean Tromans
	*/
	bool draw_information::is_valid( ) const
	{
		return device != nullptr;
	}

	/**
	Exposes the draw_information to lua.
	@param L The Lua State being initialised.
	\author Sean Tromans.
	*/
	void draw_information::lua_interface( lua_State * L )
	{
#if !defined(SUN_DISABLE_LUA)
		luabind::module( L, "rainbow" )
		[
			luabind::class_< draw_information >( "draw_information" )
				.def( luabind::constructor<graphics_device &>( ) )
				.def_readonly(	"device", &draw_information::device )

				.def_readonly(	"blend_handle",		&draw_information::blend_handle )
				.def_readonly(	"culling_handle",	&draw_information::culling_handle )
				.def_readonly(	"depth_handle",		&draw_information::depth_handle )
				.def_readonly(	"stencil_handle",	&draw_information::stencil_handle )

				.scope
				[
					luabind::def( "default_ordering",			draw_information::default_ordering )
				]
		];
#else
		NMN_UNUSED( L );
#endif
	}

	/**
	Sorts by material settings.
	@param a The first draw_information to compare.
	@param b The first draw_information to compare.
	@returns true if a compares less than b. False otherwise.
	\author Sean Tromans
	*/
	bool draw_information::default_ordering( draw_information const & a, draw_information const & b )
	{
		if ( a.device != b.device )
		{
			throw different_device_targets_exception( );
		}

		if ( !a.is_valid( ) || !b.is_valid( ) )
		{
			throw invalid_draw_information_exception( );
		}

		if ( a.blend_handle != b.blend_handle )
		{
			return a.blend_handle < b.blend_handle;
		}
		else if ( a.stencil_handle != b.stencil_handle )
		{
			return a.stencil_handle < b.stencil_handle;
		}
		else if ( a.depth_handle != b.depth_handle )
		{
			return a.depth_handle < b.depth_handle;
		}
		else if ( a.culling_handle != b.culling_handle )
		{
			return a.culling_handle < b.culling_handle;
		}
		else
		{
			return false;
		}
	}

	/**
	Tests whether the material settings for two draw_information objects are equal. Ignores mesh and positional information.
	@param a The first draw_information to compare.
	@param b The first draw_information to compare.
	@returns true if a's material is equal to b's. False otherwise.
	\author Sean Tromans
	*/
	bool draw_information::materials_equal( draw_information const & a, draw_information const & b )
	{
		if ( a.device != b.device )
		{
			throw different_device_targets_exception( );
		}

		if ( !a.is_valid( ) || !b.is_valid( ) )
		{
			throw invalid_draw_information_exception( );
		}

		return	a.blend_handle == b.blend_handle
			&&	a.stencil_handle == b.stencil_handle
			&&	a.depth_handle == b.depth_handle
			&&	a.culling_handle == b.culling_handle;
	}

};
